/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.google.code.peersim.pastry.protocol;

import java.util.UUID;

/**
 * Message used to look for resources in the pastry network. The key in the message
 * stores the resource id to look-for
 *
 * @author frusso
 * @version 0.1
 * @since 0.1
 */
class LookupResource extends PastryMessage {

  /**
   * Constructor.
   *
   * @param resourceId The resource to look for
   * @param src The sender
   * @param dst The destination
   */
  LookupResource(PastryId resourceId, PastryNode src, PastryNode dst) {
    super.setType(Type.LOOKUP_RESOURCE);
    super.setKey(resourceId);
    super.setOrignator(src);
    super.setSender(src);
    super.setDestination(dst);
  }

  /**
   * Generates an ack message stating the final node, the node owning the searched for
   * resource, has been found. The {@link LookupResourceAck} has the same number of
   * hops of this message.
   *
   * @return A positive ack
   */
  LookupResourceAck ackFinalNode(PastryResource<?> res) {
    LookupResourceAck ack = new LookupResourceAck(this.getDst(), this.getOriginalSender(), this.getId(), null, this.getKey(), res);
    ack.setOrignator(this.getOriginalSender());
    ack.setHops(this.getHops());
    return ack;
  }

  /**
   * Generates an ack message stating the final node, the node owning the searched for
   * resource, has not been found yet. The {@link LookupResourceAck} has the same number of
   * hops of this message. The ack message stores the next step advised by the sender of
   * the ack.
   *
   * @param nextStep The next advised node to contact
   * @return A negative ack
   */
  LookupResourceAck ackNonFinalNode(PastryId nextStep) {
    LookupResourceAck ack = new LookupResourceAck(this.getDst(), this.getOriginalSender(), this.getId(), nextStep, this.getKey(), null);
    ack.setOrignator(this.getOriginalSender());
    ack.setHops(this.getHops());
    return ack;
  }

  /**
   * Forwards the current message to the provided next step. The returned {@link LookupResource}
   * is a brand new instance whose number of hops equals those of the current one.
   *
   * @param nextStep The next node
   * @return The new message that must be forwarded
   */
  LookupResource forward(PastryNode nextStep) {
    LookupResource f = new LookupResource(this.getKey(), this.getOriginalSender(), nextStep);
    f.setOrignator(super.getOriginalSender());
    f.setHops(this.getHops());
    return f;
  }

  /**
   * Response message for {@link LookupResource} requests. The key stores the id of the
   * looked for resource. The correlation id ties these messages to their requests ids.
   *
   * @author frusso
   * @version 0.1
   * @since 0.1
   */
  static class LookupResourceAck extends PastryMessage {

    private PastryId nextHop;
    private UUID correlationId;
    private PastryResource<?> resource;

    /**
     * Constructor.
     *
     * @param src The sender
     * @param dst The destination
     * @param corrId The correlation id
     * @param nextStep The next step (if any)
     * @param resId The resource id
     */
    LookupResourceAck(PastryNode src, PastryNode dst, UUID corrId, PastryId nextStep, PastryId resId, PastryResource<?> res) {
      super.setType(Type.LOOKUP_RESOURCE_ACK);
      super.setKey(resId);
      super.setSender(src);
      super.setDestination(dst);
      correlationId = corrId;
      nextHop = nextStep;
      resource = res;
    }

    /**
     * If the next-hop is non-{@code null} the message is a nack and the request
     * has to be forwared to the suggested next hop, otherwise the sender is the
     * owner of the looked for resource.
     *
     * @return The next-hop or {@code null}
     */
    public PastryId getNextHop() {
      return nextHop;
    }

    /**
     * The correlation-id used to reconciliate this message to its request.
     *
     * @return The correlation-id
     */
    public UUID getCorrelationId() {
      return correlationId;
    }

    public PastryResource<?> getResource() {
      return resource;
    }
  }
}